package org.base.admin.config.security;

import org.aopalliance.intercept.MethodInvocation;
import org.base.admin.modules.base.AbstractController;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

@Component
public class MyMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
	
	@Override
	protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
			MethodInvocation invocation) {
		MyMethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(
				authentication);
		root.setThis(invocation.getThis());
		root.setPermissionEvaluator(getPermissionEvaluator());
		root.setTrustResolver(getTrustResolver());
		root.setRoleHierarchy(getRoleHierarchy());
		root.setDefaultRolePrefix(getDefaultRolePrefix());

		return root;
	}
}

class MyMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {

	private Object filterObject;
	private Object returnObject;
	private Object target;

	MyMethodSecurityExpressionRoot(Authentication a) {
		super(a);
	}

	public void setFilterObject(Object filterObject) {
		this.filterObject = filterObject;
	}

	public Object getFilterObject() {
		return filterObject;
	}

	public void setReturnObject(Object returnObject) {
		this.returnObject = returnObject;
	}

	public Object getReturnObject() {
		return returnObject;
	}

	/**
	 * Sets the "this" property for use in expressions. Typically this will be the
	 * "this" property of the {@code JoinPoint} representing the method invocation
	 * which is being protected.
	 *
	 * @param target
	 *            the target object on which the method in is being invoked.
	 */
	void setThis(Object target) {
		this.target = target;
	}

	public Object getThis() {
		return target;
	}
	
	public boolean hasMyAuthority(String... authorities) {
		if(this.target instanceof AbstractController) {
			AbstractController controller = (AbstractController) this.target;
			for(int i=0; i<authorities.length; i++) {
				authorities[i] = controller.authoritiesPrefix()+authorities[i];
			}
		}
		return hasAnyAuthority(authorities);
	}

}
